package com.jhx.common.http;

import android.os.Build;

import com.jhx.common.app.CommonModule;
import com.jhx.common.cache.SimpleCache;
import com.jhx.common.utils.Constants;
import com.jhx.common.utils.KLog;
import com.jhx.common.utils.SignUtils;
import com.jhx.common.utils.SystemConfigUtils;
import com.tencent.bugly.crashreport.CrashReport;

import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * Retrofit 封装
 *
 * @author wenqin 2017-04-13 19:33
 */

public class ApiManager {
    private static final int DEFAULT_TIMEOUT = 30;
    private static volatile ApiManager sApiManager;
    private static boolean isNewServDomainName = false;
    private static String mVersion = CommonModule.Companion.getVersion();

    public static ApiManager get() {
        if (sApiManager == null) {
            synchronized (ApiManager.class) {
                if (sApiManager == null) {
                    sApiManager = new ApiManager();
                }
            }
        }
        return sApiManager;
    }

    /**
     * 用于更改测试环境地址
     */
    public static void clear() {
        if (sApiManager != null) {
            sApiManager = null;
        }
    }

    public <T> T getApiService(Class<T> tcl) {
        return getApiService(true, tcl);
    }

    public <T> T getApiService(boolean isNewServDomainName, Class<T> tcl) {
        return getApiService(isNewServDomainName, mVersion, tcl);
    }

    public <T> T getApiService(boolean isNewServDomainName, String version, Class<T> tcl) {
        ApiManager.isNewServDomainName = isNewServDomainName;
        ApiManager.mVersion = version;
        OkHttpClient okHttpClient = genericClient();
        if (isNewServDomainName) {
            return new Retrofit.Builder()
                    .baseUrl(IPServFactory.sharedInstance().getNewServerName())
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(okHttpClient)
                    .build().create(tcl);
        } else {
           return new Retrofit.Builder()
                    .baseUrl(IPServFactory.sharedInstance().getServerName())
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(okHttpClient)
                    .build().create(tcl);
        }
    }

    /**
     * 添加统一header,超时时间,http日志打印
     *
     * @return OkHttpClient实例
     */
    private OkHttpClient genericClient() {
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {
                // 仅Debug状态下才会打印
                KLog.Companion.d("okhttp", message);
            }
        });
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);
       OkHttpClient.Builder builder = new OkHttpClient.Builder()
               .addInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                final String token = SimpleCache.Companion.get(Constants.TOKEN_ID);
                Request request;
                Request.Builder requestBuilder = null;
                if (isNewServDomainName) {
                    String mTimeStamp = System.currentTimeMillis() + "";

                    request = chain.request();
                    if (request.method().equals("GET")) {
                        String sign = makeGetParam(chain, mTimeStamp);
                        HttpUrl httpUrl = request.url()
                                .newBuilder()
                                .addQueryParameter("sign_", sign)
                                .addQueryParameter("timestamp", mTimeStamp)
                                .build();

                        requestBuilder = request.newBuilder().url(httpUrl);
                    } else if (request.method().equals("POST")) {
                        if (request.body() instanceof FormBody) {
                            HashMap<String, String> hashMap = new HashMap<>();
                            FormBody.Builder bodyBuilder = new FormBody.Builder();
                            FormBody formBody = (FormBody) request.body();

                            for (int i = 0; i < formBody.size(); i++) {
                                bodyBuilder.addEncoded(formBody.encodedName(i), formBody.encodedValue(i));
                                hashMap.put(formBody.encodedName(i), formBody.encodedValue(i));
                            }
                            hashMap.put("timestamp", mTimeStamp);
                            String sign = SignUtils.getSign(hashMap);

                            formBody = bodyBuilder
                                    .addEncoded("sign_", sign)
                                    .addEncoded("timestamp", mTimeStamp)
                                    .build();

                            requestBuilder = request.newBuilder().post(formBody);
                        }
                    }
                    if (requestBuilder != null) {
                        request = requestBuilder
                                .addHeader("platform", "Android")
                                .addHeader("sdkVersion", Build.VERSION.SDK_INT + "")
                                .addHeader("versionName", SystemConfigUtils.getVersionName())
                                .addHeader("versionCode", SystemConfigUtils.getVersionCode() + "")
                                .addHeader("version", mVersion)
                                .addHeader(token == null ? "noTID" : "tokenId", token == null ? "" : token)
                                .build();
                    }
                } else {
                    request = chain
                            .request()
                            .newBuilder()
                            .addHeader("platform", "Android")
                            .addHeader("sdkVersion", Build.VERSION.SDK_INT + "")
                            .addHeader("versionName", SystemConfigUtils.getVersionName())
                            .addHeader("versionCode", SystemConfigUtils.getVersionCode() + "")
                            .addHeader(token == null ? "noTID" : "tokenID", token == null ? "" : token)
                            .build();
                }
                return chain.proceed(request);
            }
        })
        .addInterceptor(logging)
        .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
        .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
        .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
        if (IPServFactory.sharedInstance().getServerName()
                .startsWith(IPServFactory.sharedInstance().getSchemeOfHttps())) {
            builder.sslSocketFactory(defaultSSLFactory(), createTrustAllManager());
//            信任指定证书
//            try {
//                builder.sslSocketFactory(initSSLSocketFactory());
//            } catch (KeyManagementException e) {
//                e.printStackTrace();
//            }
        }
        return builder.build();
    }

    private String makeGetParam(Interceptor.Chain chain, String mTimeStamp) {
        HashMap<String, String> hashMap = new HashMap<>();
        try {
            HttpUrl httpUrl = chain.request().url();
            if (httpUrl != null) {
                for (int i = 0; i < httpUrl.querySize(); i++) {
                    String name = httpUrl.queryParameterName(i);
                    String value = httpUrl.queryParameterValue(i);
                    hashMap.put(name, value);
                }
            }
        } catch (Exception e) {
            CrashReport.postCatchedException(e);
        }
        hashMap.put("timestamp", mTimeStamp);
        return SignUtils.getSign(hashMap);
    }

    /**
     * 信任所有证书
     * @return
     */
    private static SSLSocketFactory defaultSSLFactory() {
        SSLSocketFactory sslSocketFactory = null;
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{createTrustAllManager()}, new SecureRandom());
            sslSocketFactory = sslContext.getSocketFactory();
        } catch (Exception e) {

        }
        return sslSocketFactory;
    }

    public static X509TrustManager createTrustAllManager() {
        X509TrustManager tm = null;
        try {
            tm =   new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException {
                    //do nothing，接受任意客户端证书
                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException {
                    //do nothing，接受任意服务端证书
                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }
            };
        } catch (Exception e) {

        }
        return tm;
    }

    /**
     * 信任指定证书
     * @return
     * @throws KeyManagementException
     */
    private static SSLSocketFactory initSSLSocketFactory() throws KeyManagementException {
        String certificateName;
        //生成证书:Certificate
        CertificateFactory cf;
        SSLSocketFactory factory = null;
        try {
            cf = CertificateFactory.getInstance("X.509");
            certificateName = "jhxshop.jhxia.com.cer";
            InputStream caInput = CommonModule.Companion.getApplication().getAssets().open(certificateName);
            Certificate ca;
            try {
                ca = cf.generateCertificate(caInput);
            } finally {
                try {
                    caInput.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //初始化公钥:keyStore
            String keyType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyType);
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);
            //初始化TrustManagerFactory
            String algorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory managerFactory = TrustManagerFactory.getInstance(algorithm);
            managerFactory.init(keyStore);
            //初始化sslContext
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, managerFactory.getTrustManagers(), null);
            factory = sslContext.getSocketFactory();
        } catch (CertificateException | NoSuchAlgorithmException | KeyStoreException | IOException e) {
            e.printStackTrace();
        }
        return factory;
    }
}
